from rest_framework import viewsets, status
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.utils import timezone
from django.db.models import Count, Q
from django.contrib.auth import get_user_model
from .models import Environment, HostType, HostGroup, Host, HostMonitorData, SSHConnectionLog
from .serializers import (
    EnvironmentSerializer, HostTypeSerializer, HostGroupSerializer,
    HostSerializer, HostCreateSerializer, HostMonitorDataSerializer
)
import paramiko
import json


class EnvironmentViewSet(viewsets.ModelViewSet):
    """环境管理视图集"""
    queryset = Environment.objects.all()
    serializer_class = EnvironmentSerializer
    permission_classes = [IsAuthenticated]


class HostTypeViewSet(viewsets.ModelViewSet):
    """主机类型管理视图集"""
    queryset = HostType.objects.all()
    serializer_class = HostTypeSerializer
    permission_classes = [IsAuthenticated]


class HostGroupViewSet(viewsets.ModelViewSet):
    """主机组管理视图集"""
    queryset = HostGroup.objects.all()
    serializer_class = HostGroupSerializer
    permission_classes = [IsAuthenticated]

    @action(detail=True, methods=['get'])
    def hosts(self, request, pk=None):
        """获取主机组下的主机"""
        group = self.get_object()
        hosts = group.host_set.all()
        serializer = HostSerializer(hosts, many=True)
        return Response(serializer.data)


class HostViewSet(viewsets.ModelViewSet):
    """主机管理视图集"""
    queryset = Host.objects.all()
    permission_classes = [IsAuthenticated]

    def get_serializer_class(self):
        if self.action == 'create':
            return HostCreateSerializer
        return HostSerializer

    def get_queryset(self):
        """自定义查询集，支持搜索和过滤"""
        queryset = Host.objects.all()

        # 通用搜索
        search = self.request.query_params.get('search', None)
        if search:
            from django.db.models import Q
            queryset = queryset.filter(
                Q(hostname__icontains=search) |
                Q(ip_address__icontains=search) |
                Q(public_ip__icontains=search) |
                Q(os_type__icontains=search) |
                Q(os_version__icontains=search) |
                Q(description__icontains=search)
            )

        # 取反筛选功能：显示所有非在线状态的主机
        invert_filter = self.request.query_params.get('invert_filter', None)
        if invert_filter and invert_filter.lower() == 'true':
            # 排除在线状态的主机，显示问题主机
            queryset = queryset.exclude(status='online')

            # 如果同时指定了状态，在非在线主机中进一步筛选
            status = self.request.query_params.get('status', None)
            if status and status != 'online':
                queryset = queryset.filter(status=status)
        else:
            # 正常状态过滤
            status = self.request.query_params.get('status', None)
            if status:
                queryset = queryset.filter(status=status)

        return queryset.order_by('-created_at')

    @action(detail=True, methods=['post'])
    def test_connection(self, request, pk=None):
        """测试SSH连接"""
        host = self.get_object()

        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            # 使用密码或密钥连接
            if host.ssh_private_key:
                # 使用私钥连接
                key = paramiko.RSAKey.from_private_key_string(host.ssh_private_key)
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    pkey=key,
                    timeout=10
                )
            else:
                # 使用密码连接
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    password=host.ssh_password,
                    timeout=10
                )

            # 执行简单命令测试
            stdin, stdout, stderr = ssh.exec_command('echo "connection test"')
            result = stdout.read().decode().strip()

            ssh.close()

            return Response({
                'success': True,
                'message': 'SSH连接测试成功',
                'result': result,
                'note': '连接正常，可以进行远程操作'
            })

        except Exception as e:
            return Response({
                'success': False,
                'message': f'SSH连接测试失败: {str(e)}',
                'note': '请检查主机IP、端口、用户名、密码或密钥配置'
            }, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def execute_command(self, request, pk=None):
        """执行SSH命令"""
        host = self.get_object()
        command = request.data.get('command')

        if not command:
            return Response({
                'error': '命令不能为空'
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            # 连接主机
            if host.ssh_private_key:
                key = paramiko.RSAKey.from_private_key_string(host.ssh_private_key)
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    pkey=key,
                    timeout=10
                )
            else:
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    password=host.ssh_password,
                    timeout=10
                )

            # 执行命令
            stdin, stdout, stderr = ssh.exec_command(command)
            output = stdout.read().decode()
            error = stderr.read().decode()

            ssh.close()

            return Response({
                'success': True,
                'output': output,
                'error': error
            })

        except Exception as e:
            return Response({
                'success': False,
                'message': f'执行失败: {str(e)}'
            }, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['post'])
    def collect_info(self, request, pk=None):
        """收集主机系统信息"""
        host = self.get_object()

        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            # 连接主机
            if host.ssh_private_key:
                key = paramiko.RSAKey.from_private_key_string(host.ssh_private_key)
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    pkey=key,
                    timeout=10
                )
            else:
                ssh.connect(
                    hostname=host.ip_address,
                    port=host.ssh_port,
                    username=host.ssh_username,
                    password=host.ssh_password,
                    timeout=10
                )

            # 收集系统信息的命令
            commands = {
                'os_type': 'uname -s',  # 操作系统类型
                'os_version': 'cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d \'"\'',  # 操作系统版本
                'kernel_version': 'uname -r',  # 内核版本
                'cpu_cores': 'nproc',  # CPU核心数
                'cpu_architecture': 'uname -m',  # CPU架构
                'memory_total': 'free -m | grep Mem | awk \'{print $2}\'',  # 总内存(MB)
                'memory_info': 'free -h | grep Mem | awk \'{print $2}\'',  # 内存信息
                'disk_total': 'df -h / | tail -1 | awk \'{print $2}\'',  # 总磁盘
                'disk_info': 'df -h / | tail -1 | awk \'{print $2" "$3" "$5}\'',  # 磁盘信息
                'hostname_sys': 'hostname',  # 系统主机名
                'public_ip': 'ip addr show | grep "inet " | grep -v "127.0.0.1" | grep -v "172.16." | grep -v "192.168." | head -1 | awk \'{print $2}\' | cut -d/ -f1 || ip route get 8.8.8.8 | grep -oP "src \\K[^ ]+" || hostname -I | awk \'{print $1}\'',  # 公网IP
            }

            results = {}
            for key, command in commands.items():
                try:
                    stdin, stdout, stderr = ssh.exec_command(command)
                    output = stdout.read().decode().strip()
                    error = stderr.read().decode().strip()

                    if output and not error:
                        results[key] = output
                    else:
                        results[key] = ''
                except Exception as e:
                    results[key] = ''
                    print(f"执行命令 {command} 失败: {e}")

            ssh.close()

            # 更新主机信息
            updated_fields = []

            if results.get('os_type'):
                host.os_type = results['os_type']
                updated_fields.append('os_type')

            if results.get('os_version'):
                host.os_version = results['os_version']
                updated_fields.append('os_version')

            if results.get('kernel_version'):
                host.kernel_version = results['kernel_version']
                updated_fields.append('kernel_version')

            if results.get('cpu_cores'):
                try:
                    host.cpu_cores = int(results['cpu_cores'])
                    updated_fields.append('cpu_cores')
                except ValueError:
                    pass

            if results.get('cpu_architecture'):
                host.cpu_architecture = results['cpu_architecture']
                updated_fields.append('cpu_architecture')

            if results.get('memory_total'):
                try:
                    host.memory_total = int(results['memory_total'])
                    updated_fields.append('memory_total')
                except ValueError:
                    pass

            if results.get('memory_info'):
                host.memory_info = f"{results['memory_info']} 总内存"
                updated_fields.append('memory_info')

            if results.get('disk_info'):
                host.disk_info = results['disk_info']
                updated_fields.append('disk_info')

            if results.get('public_ip'):
                # 验证是否为有效的IP地址
                import re
                ip_pattern = r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
                if re.match(ip_pattern, results['public_ip'].strip()):
                    host.public_ip = results['public_ip'].strip()
                    updated_fields.append('public_ip')

            # 更新状态和时间
            host.status = 'online'
            host.last_check_time = timezone.now()
            updated_fields.extend(['status', 'last_check_time'])

            if updated_fields:
                host.save(update_fields=updated_fields)

            return Response({
                'success': True,
                'message': '主机信息收集成功',
                'collected_info': results,
                'updated_fields': updated_fields
            })

        except Exception as e:
            # 更新主机状态为离线
            host.status = 'error'
            host.last_check_time = timezone.now()
            host.save(update_fields=['status', 'last_check_time'])

            return Response({
                'success': False,
                'message': f'收集主机信息失败: {str(e)}'
            }, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['post'])
    def batch_collect_info(self, request):
        """批量收集所有主机信息"""
        hosts = Host.objects.all()
        results = []

        for host in hosts:
            try:
                # 直接调用收集逻辑，不通过视图方法
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

                # 连接主机
                if host.ssh_private_key:
                    key = paramiko.RSAKey.from_private_key_string(host.ssh_private_key)
                    ssh.connect(
                        hostname=host.ip_address,
                        port=host.ssh_port,
                        username=host.ssh_username,
                        pkey=key,
                        timeout=10
                    )
                else:
                    ssh.connect(
                        hostname=host.ip_address,
                        port=host.ssh_port,
                        username=host.ssh_username,
                        password=host.ssh_password,
                        timeout=10
                    )

                # 收集系统信息的命令
                commands = {
                    'os_type': 'uname -s',
                    'os_version': 'cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d \'"\'',
                    'kernel_version': 'uname -r',
                    'cpu_cores': 'nproc',
                    'cpu_architecture': 'uname -m',
                    'memory_total': 'free -m | grep Mem | awk \'{print $2}\'',
                    'memory_info': 'free -h | grep Mem | awk \'{print $2}\'',
                    'disk_total': 'df -h / | tail -1 | awk \'{print $2}\'',
                    'disk_info': 'df -h / | tail -1 | awk \'{print $2" "$3" "$5}\'',
                    'public_ip': 'ip addr show | grep "inet " | grep -v "127.0.0.1" | grep -v "172.16." | grep -v "192.168." | head -1 | awk \'{print $2}\' | cut -d/ -f1 || ip route get 8.8.8.8 | grep -oP "src \\K[^ ]+" || hostname -I | awk \'{print $1}\'',
                }

                collected_info = {}
                for key, command in commands.items():
                    try:
                        stdin, stdout, stderr = ssh.exec_command(command)
                        output = stdout.read().decode().strip()
                        error = stderr.read().decode().strip()

                        if output and not error:
                            collected_info[key] = output
                        else:
                            collected_info[key] = ''
                    except Exception:
                        collected_info[key] = ''

                ssh.close()

                # 更新主机信息
                updated_fields = []

                if collected_info.get('os_type'):
                    host.os_type = collected_info['os_type']
                    updated_fields.append('os_type')

                if collected_info.get('os_version'):
                    host.os_version = collected_info['os_version']
                    updated_fields.append('os_version')

                if collected_info.get('kernel_version'):
                    host.kernel_version = collected_info['kernel_version']
                    updated_fields.append('kernel_version')

                if collected_info.get('cpu_cores'):
                    try:
                        host.cpu_cores = int(collected_info['cpu_cores'])
                        updated_fields.append('cpu_cores')
                    except ValueError:
                        pass

                if collected_info.get('cpu_architecture'):
                    host.cpu_architecture = collected_info['cpu_architecture']
                    updated_fields.append('cpu_architecture')

                if collected_info.get('memory_total'):
                    try:
                        host.memory_total = int(collected_info['memory_total'])
                        updated_fields.append('memory_total')
                    except ValueError:
                        pass

                if collected_info.get('memory_info'):
                    host.memory_info = f"{collected_info['memory_info']} 总内存"
                    updated_fields.append('memory_info')

                if collected_info.get('disk_info'):
                    host.disk_info = collected_info['disk_info']
                    updated_fields.append('disk_info')

                if collected_info.get('public_ip'):
                    # 验证是否为有效的IP地址
                    import re
                    ip_pattern = r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
                    if re.match(ip_pattern, collected_info['public_ip'].strip()):
                        host.public_ip = collected_info['public_ip'].strip()
                        updated_fields.append('public_ip')

                # 更新状态和时间
                host.status = 'online'
                host.last_check_time = timezone.now()
                updated_fields.extend(['status', 'last_check_time'])

                if updated_fields:
                    host.save(update_fields=updated_fields)

                results.append({
                    'host_id': host.id,
                    'hostname': host.hostname,
                    'success': True,
                    'message': '信息收集成功'
                })

            except Exception as e:
                # 更新主机状态为错误
                host.status = 'error'
                host.last_check_time = timezone.now()
                host.save(update_fields=['status', 'last_check_time'])

                results.append({
                    'host_id': host.id,
                    'hostname': host.hostname,
                    'success': False,
                    'message': f'收集失败: {str(e)}'
                })

        success_count = sum(1 for r in results if r['success'])

        return Response({
            'success': True,
            'message': f'批量收集完成，成功: {success_count}/{len(results)}',
            'results': results
        })

    @action(detail=False, methods=['post'])
    def batch_import(self, request):
        """批量导入主机"""
        hosts_data = request.data

        if not isinstance(hosts_data, list):
            return Response({
                'success': False,
                'message': '数据格式错误，应为数组格式'
            }, status=status.HTTP_400_BAD_REQUEST)

        if not hosts_data:
            return Response({
                'success': False,
                'message': '导入数据不能为空'
            }, status=status.HTTP_400_BAD_REQUEST)

        imported_count = 0
        errors = []

        for i, host_data in enumerate(hosts_data):
            try:
                # 验证必填字段
                required_fields = ['hostname', 'ip_address', 'ssh_port', 'ssh_username', 'environment', 'host_type']
                for field in required_fields:
                    if field not in host_data or not host_data[field]:
                        raise ValueError(f'缺少必填字段: {field}')

                # 检查主机名是否已存在
                if Host.objects.filter(hostname=host_data['hostname']).exists():
                    errors.append(f'第{i+1}行: 主机名 {host_data["hostname"]} 已存在')
                    continue

                # 检查IP是否已存在
                if Host.objects.filter(ip_address=host_data['ip_address']).exists():
                    errors.append(f'第{i+1}行: IP地址 {host_data["ip_address"]} 已存在')
                    continue

                # 查找环境
                try:
                    environment = Environment.objects.get(name=host_data['environment'])
                except Environment.DoesNotExist:
                    errors.append(f'第{i+1}行: 环境 {host_data["environment"]} 不存在')
                    continue

                # 查找主机类型
                try:
                    host_type = HostType.objects.get(name=host_data['host_type'])
                except HostType.DoesNotExist:
                    errors.append(f'第{i+1}行: 主机类型 {host_data["host_type"]} 不存在')
                    continue

                # 创建主机
                host = Host.objects.create(
                    hostname=host_data['hostname'],
                    ip_address=host_data['ip_address'],
                    ssh_port=int(host_data['ssh_port']),
                    ssh_username=host_data['ssh_username'],
                    ssh_password=host_data.get('ssh_password', ''),
                    environment=environment,
                    host_type=host_type,
                    description=host_data.get('description', ''),
                    status='offline',  # 默认状态为离线
                    created_by=request.user  # 设置创建者
                )

                imported_count += 1

            except Exception as e:
                errors.append(f'第{i+1}行: {str(e)}')

        response_data = {
            'success': True,
            'imported_count': imported_count,
            'total_count': len(hosts_data),
            'message': f'导入完成，成功: {imported_count}/{len(hosts_data)}'
        }

        if errors:
            response_data['errors'] = errors
            response_data['message'] += f'，失败: {len(errors)}'

        return Response(response_data)

    @action(detail=True, methods=['get'])
    def monitor_data(self, request, pk=None):
        """获取主机监控数据"""
        host = self.get_object()
        monitor_data = HostMonitorData.objects.filter(host=host).order_by('-collected_at')[:100]
        serializer = HostMonitorDataSerializer(monitor_data, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['post'])
    def batch_test_connection(self, request):
        """批量异步测试连接"""
        host_ids = request.data.get('host_ids', [])

        if not host_ids:
            # 如果没有指定主机ID，则测试所有主机
            host_ids = list(Host.objects.values_list('id', flat=True))

        try:
            from .tasks import check_all_hosts_status

            # 创建异步任务检测指定主机
            task = check_all_hosts_status.delay()

            return Response({
                'success': True,
                'message': f'已启动批量异步连接测试任务，共 {len(host_ids)} 台主机',
                'task_id': task.id,
                'host_count': len(host_ids),
                'note': '测试结果将通过 WebSocket 实时推送'
            })
        except Exception as e:
            return Response({
                'success': False,
                'message': f'启动批量异步测试任务失败: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=False, methods=['post'])
    def batch_delete(self, request):
        """批量删除主机"""
        host_ids = request.data.get('host_ids', [])

        if not host_ids:
            return Response({
                'success': False,
                'message': '请提供要删除的主机ID列表'
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 获取要删除的主机
            hosts_to_delete = Host.objects.filter(id__in=host_ids)
            deleted_count = hosts_to_delete.count()

            if deleted_count == 0:
                return Response({
                    'success': False,
                    'message': '没有找到要删除的主机'
                }, status=status.HTTP_404_NOT_FOUND)

            # 记录删除的主机信息
            deleted_hosts = list(hosts_to_delete.values('id', 'hostname'))

            # 执行批量删除
            hosts_to_delete.delete()

            return Response({
                'success': True,
                'message': f'成功删除 {deleted_count} 台主机',
                'deleted_count': deleted_count,
                'deleted_hosts': deleted_hosts
            })

        except Exception as e:
            return Response({
                'success': False,
                'message': f'批量删除失败: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)




    @action(detail=False, methods=['post'])
    def batch_collect_info(self, request):
        """异步收集主机信息"""
        try:
            from .tasks import collect_host_info

            host_ids = request.data.get('host_ids', [])
            if not host_ids:
                # 如果没有指定主机，收集所有主机信息
                host_ids = list(Host.objects.values_list('id', flat=True))

            tasks = []
            for host_id in host_ids:
                task = collect_host_info.delay(host_id)
                tasks.append({
                    'host_id': host_id,
                    'task_id': task.id
                })

            return Response({
                'success': True,
                'message': f'已为 {len(host_ids)} 台主机创建信息收集任务',
                'tasks': tasks
            })
        except Exception as e:
            return Response({
                'success': False,
                'message': f'启动异步任务失败: {str(e)}'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @action(detail=False, methods=['get'])
    def monitoring_status(self, request):
        """获取 Celery 监控服务状态"""
        try:
            from celery import current_app

            # 检查 Celery worker 是否在线
            inspect = current_app.control.inspect()
            active_workers = inspect.active()

            if active_workers:
                worker_count = len(active_workers)
                return Response({
                    'monitoring_active': True,
                    'worker_count': worker_count,
                    'message': f'实时监控服务正在运行，{worker_count} 个 Worker 在线'
                })
            else:
                return Response({
                    'monitoring_active': False,
                    'worker_count': 0,
                    'message': '实时监控服务未运行，请启动监控服务'
                })
        except Exception as e:
            return Response({
                'monitoring_active': False,
                'message': f'无法连接到实时监控服务: {str(e)}'
            })


class HostMonitorDataViewSet(viewsets.ReadOnlyModelViewSet):
    """主机监控数据视图集"""
    queryset = HostMonitorData.objects.all()
    serializer_class = HostMonitorDataSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        queryset = super().get_queryset()
        host_id = self.request.query_params.get('host_id')
        if host_id:
            queryset = queryset.filter(host_id=host_id)
        return queryset


# DatabaseInstanceViewSet 和 SQLAuditLogViewSet 已移动到 sql_management 应用中


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def dashboard_stats(request):
    """获取仪表盘统计数据"""
    try:
        User = get_user_model()

        # 主机统计
        total_hosts = Host.objects.count()
        host_status_stats = Host.objects.values('status').annotate(count=Count('status'))

        # 转换主机状态统计为字典
        host_status = {
            'online': 0,
            'offline': 0,
            'maintenance': 0,
            'error': 0
        }

        for stat in host_status_stats:
            status_key = stat['status']
            if status_key in host_status:
                host_status[status_key] = stat['count']

        # 用户统计
        total_users = User.objects.filter(is_active=True).count()

        # 数据库实例统计
        try:
            from sql_management.models import DatabaseInstance
            total_databases = DatabaseInstance.objects.filter(is_active=True).count()
        except ImportError:
            total_databases = 0

        # 待审核SQL统计
        try:
            from sql_management.models import SQLRequest
            pending_sqls = SQLRequest.objects.filter(status='pending').count()
        except ImportError:
            pending_sqls = 0

        # 最近登录记录
        recent_logins = []
        try:
            # 获取最近的SSH连接记录作为登录记录
            recent_connections = SSHConnectionLog.objects.select_related('user', 'host').filter(
                status='connected'
            ).order_by('-connect_time')[:10]

            for conn in recent_connections:
                recent_logins.append({
                    'username': conn.user.username,
                    'ip_address': conn.source_ip or 'Unknown',
                    'login_time': conn.connect_time.strftime('%Y-%m-%d %H:%M:%S'),
                    'host': conn.host.hostname
                })
        except Exception as e:
            # 如果获取失败，使用默认数据
            recent_logins = [
                {
                    'username': request.user.username,
                    'ip_address': request.META.get('REMOTE_ADDR', 'Unknown'),
                    'login_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S'),
                    'host': 'Web Console'
                }
            ]

        return Response({
            'stats': {
                'totalHosts': total_hosts,
                'totalUsers': total_users,
                'totalDatabases': total_databases,
                'pendingSQLs': pending_sqls
            },
            'hostStatus': host_status,
            'recentLogins': recent_logins
        })

    except Exception as e:
        return Response({
            'error': f'获取仪表盘数据失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
